﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Alex2
{
    public class Search
    {
        private List<Point> close = new List<Point>();
        private List<Point> open = new List<Point>();
        private List<NodeData> nodes = new List<NodeData>();
        private List<Point> answer = new List<Point>();

        public Search()
        {
        }

        public int getG(Point parent, Point current)
        {
            int what = 0;

            if (parent.X == current.X)
            {
                if (parent.Y - 1 == current.Y || parent.Y + 1 == current.Y)
                    what = 10;
            }

            else if (parent.Y == current.Y)
            {
                if (parent.X - 1 == current.X || parent.X + 1 == current.X)
                    what = 10;
            }

            else
                what = 14;

            return what;
        }

        public int getH(Point current, Point goal)
        {
            int distance = 0;

            if (current.Y > goal.Y)
                distance = current.Y - goal.Y;

            else if (current.Y < goal.Y)
                distance = goal.Y - current.Y;

            if (current.X > goal.X)
                distance = distance + (current.X - goal.X);

            else if (current.X < goal.X)
                distance = distance + (goal.X - current.X);

            return distance;
        }

        public Point getBestF(List<Point> listahan, Point parent, Point end, List<NodeData> noodle)
        {
            Point best = new Point();
            int minF = 99999, minF2 = 99999;
            int tempF = 0;
            int count = 0;
            List<Point> tempo = new List<Point>();

            if (listahan.Count == 1)
                return listahan.ElementAt(0);

            else
            {
                //  System.out.println("Listahan size is "+listahan.size());
                for (int i = 0; i < listahan.Count(); i++)
                {
                    // tempF = getG(parent, listahan.get(i)) + getH(listahan.get(i), end);
                    tempF = noodle.ElementAt(getIndex(noodle, listahan.ElementAt(i))).getF();
                    if (tempF < minF)
                    {
                        //count++;
                        minF = tempF;
                        best = listahan.ElementAt(i);
                        //tempo.add(best);
                    }
                }
            }

          
            return best;
        }

        public int getIndex(List<NodeData> nd, Point p)
        {
            int idex = 0;
            for (int i = 0; i < nd.Count; i++)
            {
                if (nd.ElementAt(i).getMoi().Equals(p))
                    idex = i;
            }

            return idex;
        }

        public Boolean nodeHas(List<NodeData> noo, Point p)
        {
            Boolean has = false;

            for (int t = 0; t < noo.Count; t++)
            {
                if (noo.ElementAt(t).getMoi().Equals(p))
                    has = true;
            }
            return has;
        }

        private Color[,] TextureTo2DArray(Texture2D texture)
        {
            Color[] colors1D = new Color[texture.Width * texture.Height];
            texture.GetData(colors1D);
            Color[,] colors2D = new Color[texture.Width, texture.Height];
            for (int x = 0; x < texture.Width; x++)
                for (int y = 0; y < texture.Height; y++)
                    colors2D[x, y] = colors1D[x + y * texture.Width];

            return colors2D;
        }

        public void getPath(Point start, Point goal, Texture2D imahe)
        {
            Boolean isReach = false;
            open.Add(start);
            Point n; //yng green
            Point temp = new Point();
            Boolean doGH = false;
            List<Point> neighbor = new List<Point>();
            Color[,] groundColors = TextureTo2DArray(imahe);

            while (!isReach)
            {
                n = getBestF(open, start, goal, nodes);

              
                open.Remove(n);
                close.Add(n);

                if (n.X == goal.X && n.Y == goal.Y)
                    isReach = true;


                else
                {
                    for (int d = 0; d < 8; d++)
                    {
                        switch (d)
                        {
                            case 0: if (n.X - 1 >= 0 && n.Y - 1 >= 0)
                                {
                                    temp = new Point(n.X - 1, n.Y - 1);
                                    neighbor.Add(temp);
                                    doGH = true;
                                }
                                break;

                            case 1: if (n.Y - 1 >= 0 )
                                {
                                    temp = new Point(n.X, n.Y - 1);
                                    neighbor.Add(temp);
                                    doGH = true;

                                }
                                break;

                            case 2: if (n.X + 1 <1366 && n.Y - 1 >= 0)
                                {
                                    temp = new Point(n.X + 1, n.Y - 1);
                                    neighbor.Add(temp);
                                    doGH = true;
                                }
                                break;

                            case 3: if (n.X - 1 >= 0 )
                                {
                                    temp = new Point(n.X - 1, n.Y);
                                    neighbor.Add(temp);
                                    doGH = true;
                                }
                                break;

                            case 4: if (n.X + 1 < 1366)
                                {
                                    temp = new Point(n.X + 1, n.Y);
                                    neighbor.Add(temp);
                                    doGH = true;
                                }
                                break;

                            case 5: if (n.X - 1 >= 0 && n.Y + 1 < 767)
                                {
                                    temp = new Point(n.X - 1, n.Y + 1);
                                    neighbor.Add(temp);
                                    doGH = true;
                                }
                                break;

                            case 6: if (n.Y + 1 < 767 )
                                {
                                    temp = new Point(n.X, n.Y + 1);
                                    neighbor.Add(temp);
                                    doGH = true;
                                   
                                }
                                break;

                            case 7: if (n.X + 1 < 1366 && n.Y + 1 < 767 )
                                {
                                    temp = new Point(n.X + 1, n.Y + 1);
                                    neighbor.Add(temp);
                                    doGH = true;
                                    
                                }
                                break;
                        } //end of switch
                        System.Diagnostics.Debug.WriteLine("exit here ");
                        if (doGH)
                        {
                            //if(!nodes.contains(new NodeData(getG(start,temp),getH(temp,goal),getG(start,temp)+getH(temp,goal),n,temp)))
                            //     nodes.add(new NodeData(getG(start,temp),getH(temp,goal),getG(start,temp)+getH(temp,goal),n,temp));

                            //if(!nodes.contains(new NodeData(getG(n,temp),getH(temp,goal),getG(n,temp)+getH(temp,goal),n,temp)))
                            if (!nodeHas(nodes, temp))
                                nodes.Add(new NodeData(getG(n, temp), getH(temp, goal), getG(n, temp) + getH(temp, goal), n, temp));

                            //nodes.get(getIndex(nodes,temp)).getF() > getG(start,temp)+getH(temp,goal)
                            if (close.Contains(temp) && nodes.ElementAt(getIndex(nodes, temp)).getG() > getG(n, temp)) //start
                            {
                                nodes.ElementAt(getIndex(nodes, temp)).setG(getG(n, temp)); //staet
                                // nodes.get(getIndex(nodes,temp)).setH(getH(temp,goal));
                                nodes.ElementAt(getIndex(nodes, temp)).setF();
                                nodes.ElementAt(getIndex(nodes, temp)).setParent(n);
                            }
                            //nodes.get(getIndex(nodes,temp)).getF() > getG(start,temp)+getH(temp,goal)
                            else if (open.Contains(temp) && nodes.ElementAt(getIndex(nodes, temp)).getG() > getG(n, temp)) //start
                            {
                                //System.out.println("OPPA is "+temp.toString()+" "+nodes.get(getIndex(nodes,temp)).getMoi());
                                //System.out.println("GAngnam is "+nodes.get(getIndex(nodes,temp)).getMoi());
                                nodes.ElementAt(getIndex(nodes, temp)).setG(getG(n, temp)); //start
                                //nodes.get(getIndex(nodes,temp)).setH(getH(temp,goal));
                                nodes.ElementAt(getIndex(nodes, temp)).setF();
                                nodes.ElementAt(getIndex(nodes, temp)).setParent(n);
                            }

                            else if (!open.Contains(temp) && !close.Contains(temp))
                            {
                                open.Add(temp);
                                nodes.ElementAt(getIndex(nodes, temp)).setG(getG(n, temp)); //start
                                nodes.ElementAt(getIndex(nodes, temp)).setF();
                                nodes.ElementAt(getIndex(nodes, temp)).setParent(n);

                            }


                            doGH = false;
                        }
                    }//end of for

                    //for(int d=0; d<neighbor.size()+1;d++){
                    //  System.out.println("yo");
                    //neighbor.remove(0);}
                    neighbor.Clear();  //HERE!!!!!
                }

            }//ens of while statement
            //for(int f=0; f<close.size();f++)
            //    System.out.printf("it is "+close.get(f));
            //System.out.println(""); 
            //System.out.println("Parent node is "+nodes.get(getIndex(nodes, new Point(2,1))).getParent());
            //System.out.println("Parent node is "+nodes.get(getIndex(nodes, new Point(3,4))).getParent());
            //System.out.println("Parent node is "+nodes.get(getIndex(nodes, new Point(2,2))).getParent());
            //return isReach;
            Point temPoint = new Point();

            temPoint = goal;
            while (!temPoint.Equals(start))
            {
                temPoint = nodes.ElementAt(getIndex(nodes, temPoint)).getParent();
                answer.Add(temPoint);
                //System.out.println("wrong is "+temPoint);
                System.Diagnostics.Debug.WriteLine("Parent node is: " + temPoint.ToString());
            }

        }

    }

}
